package com.lightsaber.cut;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import com.lightsaber.cut.entity.Component;
import com.lightsaber.cut.entity.ComponentPool;
import com.lightsaber.cut.entity.Original;
import com.lightsaber.cut.entity.SortUtil;
import com.lightsaber.cut.func.Point;
import com.lightsaber.cut.func.Solutions;
import com.lightsaber.cut.func.TwoDimentionFunc;

/**
 * 
 * 
 * @author LiuJian
 */
public class App {

    private static Integer A = null;
    private static Integer B = null;
    /**
     * 允许最大剩余边角料
     */
    private static List<Integer> FIX_SURPLUSES = new ArrayList<Integer>();
    public static Boolean FIX_IN_GROUP;
    public static final int FIX_MOVE = 50;

    public static int POOL_GROUP_SIZE;
    public static int POOL_GROUP_SORT = 1000;

    private static Integer MAX_SURPLUS;

    private static ComponentPool COMPONENTPOOL = new ComponentPool();

    public static void main(String[] args) {

        try {
            readParams();

            Point totalBetterPoint = null;

            if (POOL_GROUP_SIZE > 0) {// 分组
                System.out.println("一次分组COMPONENTPOOL.getComponentPool().zise = "
                        + COMPONENTPOOL.getComponentPool().size());
                // 分组之前混淆顺序
                SortUtil.RandomSortComponent(COMPONENTPOOL.getComponentPool());
                List<Point> betterPoints = groupCut(COMPONENTPOOL);

                // step2: 综合各个分组的结果
                totalBetterPoint = new Point(0, 0, new ComponentPool(), new ArrayList<Original>());

                for (Point p : betterPoints) {
                    updateBetterPoint(totalBetterPoint, p);
                }

                // step3: 再次对总结果剩余料分组切割
                System.out.println("二次分组 totalBetterPoint.getLastPool().zise = "
                        + totalBetterPoint.getLastPool().getComponentPool().size());

                // 分组之前混淆顺序
                SortUtil.RandomSortComponent(totalBetterPoint.getLastPool().getComponentPool());
                betterPoints = groupCut(totalBetterPoint.getLastPool());
                totalBetterPoint.setLastPool(new ComponentPool());

                // step4: 再次对总结果剩余料分组切割， 综合各个分组的结果
                for (Point p : betterPoints) {
                    updateBetterPoint(totalBetterPoint, p);
                }

                // step3: 综合最后一组的结果
                System.out.println("两次分组后全部运行 totalBetterPoint.getLastPool().zise = "
                        + totalBetterPoint.getLastPool().getComponentPool().size());

                Point lastBetterPoint = control(true, totalBetterPoint.getLastPool());
                totalBetterPoint.setLastPool(new ComponentPool());

                updateBetterPoint(totalBetterPoint, lastBetterPoint);

            } else {// 不分组

                totalBetterPoint = control(true, COMPONENTPOOL);
            }

            System.out.println("y(min) = (-a/b)*x + l/b");
            System.out.println("y(max) = (-a/b)*x + l/(b-m)");
            System.out.println("x(max) = l/(a-m)\r\n");

            System.out.println("最优方案:");
            Collections.sort(totalBetterPoint.getOriginals());
            System.out.println(totalBetterPoint);

            // 得到最后结果
            giveResult(totalBetterPoint);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void updateBetterPoint(Point totalBetterPoint, Point betterPoint) {
        totalBetterPoint.setX(totalBetterPoint.getX() + betterPoint.getX());
        totalBetterPoint.setY(totalBetterPoint.getY() + betterPoint.getY());
        totalBetterPoint.getOriginals().addAll(betterPoint.getOriginals());
        totalBetterPoint.getLastPool().getComponentPool().addAll(betterPoint.getLastPool().getComponentPool());
    }

    private static List<Point> groupCut(ComponentPool groupComponentPool) throws Exception {
        List<Point> betterPoints = new ArrayList<Point>();

        // step1: 分组切割
        for (int i = 0; i < 100; i++) {
            ComponentPool componentPoolGroup = groupComponentPool.cloneGroup(i);
            // 最后跳出
            if (componentPoolGroup.getComponentPool().size() == 0) {
                break;
            }

            Point betterPoint = control(FIX_IN_GROUP, componentPoolGroup);
            betterPoints.add(betterPoint);

            // 最后跳出
            if (componentPoolGroup.getComponentPool().size() < POOL_GROUP_SIZE) {
                break;
            }
        }

        return betterPoints;
    }

    /**
     * 分段切割函数
     * 
     * @param cutFix
     * @param componentPoolSegment
     * @throws Exception
     */
    private static Point control(boolean cutFix, ComponentPool componentPoolSegment) throws Exception {
        System.out.println("componentPoolSegment.size=" + componentPoolSegment.getComponentPool().size());
        // 切之前先排序
        componentPoolSegment.sort();

        ComponentPool componentPoolCloneA = componentPoolSegment.clone();
        List<Original> originalA = componentPoolCloneA.cut(A, MAX_SURPLUS);
        int aMax = originalA.size();

        Solutions solutions = null;

        // 下1种料的时候, 方案中留下唯一点
        if (B == null) {
            solutions = new Solutions();
            Point p = new Point(aMax, 0);
            p.setLastPool(componentPoolCloneA);
            p.setOriginals(originalA);
            solutions.getSolutionAll().add(p);
        }

        // 下2种料的时候
        if (B != null) {
            ComponentPool componentPoolCloneB = componentPoolSegment.clone();
            int bMax = componentPoolCloneB.cut(B, MAX_SURPLUS).size();

            TwoDimentionFunc twoDimentionFunc = new TwoDimentionFunc(componentPoolSegment.getTotalLength(), A, B,
                    MAX_SURPLUS);
            solutions = twoDimentionFunc.getValidPoints(aMax, bMax);
            System.out.println(solutions.toString());

            Map<String, Point> pointMap = solutions.mapping();

            System.out.println(String.format("开始模拟实际切割(%d料优先)...................", A));
            for (int x = 0; x <= aMax; x++) {
                ComponentPool poolClone = componentPoolSegment.clone();

                List<Original> originalsA = poolClone.cut(A, MAX_SURPLUS, x);
                List<Original> originalsB = poolClone.cut(B, MAX_SURPLUS);

                Point p = pointMap.get(x + "-" + originalsB.size());
                if (p != null) {
                    originalsA.addAll(originalsB);

                    p.setOriginals(originalsA);
                    p.setLastPool(poolClone);
                }
            }
            System.out.println(solutions.toStringExperiment());

            System.out.println(String.format("开始模拟实际切割(%d料优先)...................", B));
            for (int y = 0; y <= bMax; y++) {
                ComponentPool poolClone = componentPoolSegment.clone();

                List<Original> originalsB = poolClone.cut(B, MAX_SURPLUS, y);
                List<Original> originalsA = poolClone.cut(A, MAX_SURPLUS);

                Point p = pointMap.get(originalsA.size() + "-" + y);
                if (p != null) {
                    // 前面的实验结果更理想, 跳过
                    if (p.getLastPool() != null && p.getLastPool().getTotalLength() <= poolClone.getTotalLength()) {
                        continue;
                    }

                    originalsA.addAll(originalsB);

                    p.setOriginals(originalsA);
                    p.setLastPool(poolClone);

                }
            }
            System.out.println(solutions.toStringExperiment());
        }

        List<Point> solutionAll = solutions.getSolutionAll();

        System.out.println("开始找最优点...................\r\n");
        Point pointBetter = null;
        for (Point point : solutionAll) {

            if (point.getOriginals() != null) {
                if (pointBetter == null) {// 第一个
                    pointBetter = point;
                    continue;
                }

                if (point.getLastPool().getTotalLength() < pointBetter.getLastPool().getTotalLength()) {
                    pointBetter = point;
                }
            }
        }

        if (cutFix) {
            System.out.println("开始切割余固定长度的尺寸...................");
            List<Original> originalsFixA = pointBetter.getLastPool().cutFix(A, FIX_SURPLUSES);
            pointBetter.setX(pointBetter.getX() + originalsFixA.size());
            pointBetter.getOriginals().addAll(originalsFixA);

            if (B != null) {
                List<Original> originalsFixB = pointBetter.getLastPool().cutFix(B, FIX_SURPLUSES);
                pointBetter.setY(pointBetter.getY() + originalsFixB.size());
                pointBetter.getOriginals().addAll(originalsFixB);
            }
        }

        return pointBetter;

    }

    /**
     * @throws Exception
     *             得到最后结果
     * 
     * @param pointBetter
     * @throws
     */
    private static void giveResult(Point pointBetter) throws Exception {
        File file = saveResult(pointBetter);

        Scanner sc = new Scanner(System.in);
        String speak = null;

        while (true) {
            System.out.println("是否打印(Y/N):");
            speak = sc.next();

            if ("Y".equalsIgnoreCase(speak)) {

                try {
                    Runtime.getRuntime().exec("notepad " + file.getAbsolutePath());
                } catch (IOException e) {
                    e.printStackTrace();
                }

                break;
            }

            if ("N".equalsIgnoreCase(speak)) {
                break;
            }
        }
    }

    /**
     * 保存最后结果到文件
     * 
     * @param pointBetter
     * @throws Exception
     */
    private static File saveResult(Point pointBetter) throws Exception {
        File file = null;
        OutputStreamWriter writer = null;
        DateFormat df = new SimpleDateFormat("yy-MM-dd");
        DateFormat timef = new SimpleDateFormat("hh-mm-ss");
        Date now = new Date();
        String dirPath = "/切割方案";

        try {
            Date validDate = df.parse("14-06-01");
            if (now.compareTo(validDate) > 0) {
                throw new Exception("无法创建文件");
            }

            file = new File(dirPath);
            if (!file.exists()) {
                if (!file.mkdir()) {
                    throw new Exception("无法创建文件夹:" + file.getPath());
                }
            }

            file = new File(file, df.format(now));
            if (!file.exists()) {
                if (!file.mkdir()) {
                    throw new Exception("无法创建文件夹:" + file.getPath());
                }
            }

            file = new File(file, timef.format(now) + ".txt");
            writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            writer.write(pointBetter.toString());

        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        } finally {

            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                }
            }
        }

        System.out.println("成功保存到文件: " + file.getAbsolutePath());
        return file;
    }

    private static void readParams() throws Exception {
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream("app.properties")));

            String line = null;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("#") || "".equals(line)) {
                    continue;
                }

                if (line.startsWith("LS")) {
                    line = line.substring(line.indexOf("=") + 1);
                    String[] ls = line.split(",");
                    A = Integer.valueOf(ls[0].trim()) * 10;
                    if (ls.length > 1) {
                        B = Integer.valueOf(ls[1].trim()) * 10;
                    }

                    continue;
                }

                if (line.startsWith("MAX_SURPLUS")) {
                    line = line.substring(line.indexOf("=") + 1);
                    MAX_SURPLUS = Integer.valueOf(line.trim()) * 10;

                    continue;
                }

                if (line.startsWith("POOL_GROUP_SIZE")) {
                    line = line.substring(line.indexOf("=") + 1);
                    POOL_GROUP_SIZE = Integer.valueOf(line.trim());

                    continue;
                }
                if (line.startsWith("POOL_GROUP_SORT")) {
                    line = line.substring(line.indexOf("=") + 1);
                    POOL_GROUP_SORT = Integer.valueOf(line.trim()).intValue();
                }
                
                if (line.startsWith("FIX_IN_GROUP")) {
                    line = line.substring(line.indexOf("=") + 1);
                    FIX_IN_GROUP = Boolean.valueOf(line.trim());

                    continue;
                }

                if (line.startsWith("FIX_SURPLUSES")) {
                    line = line.substring(line.indexOf("=") + 1);
                    String[] fixSurpluses = line.split(",");
                    for (String fixSurplus : fixSurpluses) {
                        FIX_SURPLUSES.add(Integer.valueOf(fixSurplus.trim()) * 10);
                    }

                    continue;
                }

                String sequenceStr = null;
                Integer sequence = null;
                if (line.startsWith("LENGTHS")) {

                    while ((line = reader.readLine()) != null) {
                        if (line.startsWith("#") || "".equals(line)) {
                            continue;
                        }

                        // --------------------- 填充尺寸池 --------------------start
                        int indexOfBracket = line.indexOf("(");

                        sequenceStr = line.substring(0, indexOfBracket);
                        sequence = Integer.valueOf(sequenceStr.trim());

                        String[] lengths = line.substring(indexOfBracket + 1, line.indexOf(")")).split(",");
                        Component component = null;

                        for (String length : lengths) {
                            Float lengthF = Float.valueOf(length.trim()) * 1000;

                            component = new Component();
                            component.setLength(lengthF.intValue());
                            component.setSequence(sequence);
                            COMPONENTPOOL.put(component);
                        }
                        // --------------------- 填充尺寸池 --------------------end
                    }

                    System.out.println(COMPONENTPOOL.toString());
                    break;
                }

            }

            System.out.println("成功读取配置文件 app.properties!\r\n");

        } catch (Exception e) {
            System.out.println("失败读取配置文件 app.properties!");
            throw new Exception(e.getMessage(), e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                }
            }
        }
    }
}
